<template>
  <div class="bpmn-container">
    <div class="header">
      <div class="header-left">
        <el-button type="danger" @click="handleCloseFlowStatus">关闭</el-button>
        <h2>{{ title }}</h2>
      </div>

      <div class="controls">
        <el-button-group>
          <el-button>{{ Math.round(zoom * 100) }}%</el-button>
          <el-tooltip content="重置视图" placement="bottom">
            <el-button :icon="Refresh" @click="resetZoom"/>
          </el-tooltip>
          <el-tooltip content="拖拽画布" placement="bottom">
            <el-button
                :icon="Rank"
                @click="toggleDragMode"
                :type="isDragMode ? 'primary' : ''"
            />
          </el-tooltip>
          <el-tooltip content="显示/隐藏网格" placement="bottom">
            <el-button
                :icon="Grid"
                :type="showGrid ? 'primary' : ''"
                @click="toggleGrid"
            />
          </el-tooltip>
        </el-button-group>
      </div>
    </div>

    <div id="bpmn-canvas" ref="canvas"
         :class="['bpmn-canvas-wrapper', { 'drag-mode': isDragMode, 'with-grid': showGrid }]"
         @mousedown="handleMouseDown"
         @mousemove="handleMouseMove"
         @mouseup="handleMouseUp"
         @mouseleave="handleMouseLeave"
         @wheel="handleWheel">
      <!-- 网格背景层 -->
      <svg v-if="showGrid" ref="gridSvg" class="grid-background">
        <defs>
          <pattern id="grid-pattern" height="20" patternUnits="userSpaceOnUse" width="20">
            <path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(0, 0, 0, 0.1)" stroke-width="0.5"/>
          </pattern>
        </defs>
        <rect fill="url(#grid-pattern)" height="100%" width="100%"/>
      </svg>
    </div>

    <div v-if="loading" class="loading-overlay">
      <el-icon class="loading-icon">
        <Loading/>
      </el-icon>
    </div>

    <div v-if="activeNode" class="node-details">
      <h3>{{ activeNode.name || activeNode.id }}</h3>
      <div class="detail-row">
        <span class="label">ID:</span>
        <span class="value">{{ activeNode.id }}</span>
      </div>
      <div v-if="activeNode.approvers" class="detail-row">
        <span class="label">审批人:</span>
        <div class="approvers">
          <el-tag
              v-for="(approver, index) in activeNode.approvers"
              :key="index"
              class="approver-tag"
              size="small"
              type="success"
          >
            {{ approver }}
          </el-tag>
        </div>
      </div>
      <div class="detail-row">
        <span class="label">状态:</span>
        <el-tag :type="getStatusType(activeNode.status)">{{ getStatusStr(activeNode.status) }}</el-tag>
      </div>
      <div v-if="activeNode.startTime" class="detail-row">
        <span class="label">开始时间:</span>
        <span class="value">{{ activeNode.startTime }}</span>
      </div>
      <div v-if="activeNode.endTime" class="detail-row">
        <span class="label">结束时间:</span>
        <span class="value">{{ activeNode.endTime }}</span>
      </div>
      <div v-if="activeNode.duration > 0" class="detail-row">
        <span class="label">耗时:</span>
        <span class="value">{{ formatDuration(activeNode.duration) }}</span>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import {ref, onMounted, onBeforeUnmount} from 'vue'
import {ElButton, ElButtonGroup, ElTooltip, ElTag, ElIcon, ElMessage} from 'element-plus'
import {Refresh, Loading, Rank, Grid} from '@element-plus/icons-vue'
import BpmnViewer from 'bpmn-js/dist/bpmn-viewer.production.min.js'
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import {
  getXmlStrByProcessInstanceId,
  getNodeDetails,
  getHighlighted
} from '@/api/workflow/bpmView'
import {message} from "@/utils/ElmessasgeUtils";
import {formatDuration} from "@/utils/dateUtils";
import router from '@/router'
import {useRoute} from 'vue-router';

const route = useRoute();
const processInstanceId = route.params.processInstanceId;

console.log("路由参数", processInstanceId)

// 响应式数据
const canvas = ref<HTMLElement | null>(null)
const gridSvg = ref<HTMLElement | null>(null)
const bpmnViewer = ref<any>(null)
const title = ref('流程预览')
const loading = ref(true)
const zoom = ref(1)
const activeNode = ref<any>(null)
const nodeDetailsCache = ref<Record<string, any>>({})
const showGrid = ref(true) // 默认显示网格

// 拖拽相关状态
const isDragging = ref(false)
const isDragMode = ref(true)
const dragStart = ref({x: 0, y: 0})
const currentViewbox = ref({x: 0, y: 0, width: 0, height: 0})

// 初始化流程图
onMounted(async () => {
  if (!canvas.value) return

  bpmnViewer.value = new BpmnViewer({
    container: canvas.value
  })

  try {
    console.log('初始化流程图开始')

    // 1. 获取流程定义XML
    const res = await getXmlStrByProcessInstanceId(processInstanceId)
    let modelXml: string

    if (res.data.code === 200) {
      modelXml = res.data.data
      console.log('成功获取流程XML')
    } else {
      console.error('获取流程XML失败:', res)
      return
    }

    // 2. 导入XML
    const importResult = await bpmnViewer.value.importXML(modelXml)
    console.log('XML导入结果:', importResult)

    if (importResult.warnings && importResult.warnings.length > 0) {
      console.warn('XML导入警告:', importResult.warnings)
    }

    // 3. 等待BPMN.js完成渲染
    await new Promise(resolve => setTimeout(resolve, 300))

    // 4. 居中显示流程图
    await centerDiagram()

    let highlightedNodes: any = [];
    let highlightedFlows: any = [];

    // 5. 获取高亮节点
    const highLightedResp = await getHighlighted(processInstanceId)
    if (highLightedResp.data.code === 200) {
      highlightedNodes = highLightedResp.data.data.highLightedNodes;
      highlightedFlows = highLightedResp.data.data.highLightedFlows;
    } else {
      message("获取高亮节点失败", "error")
    }

    console.log('高亮节点:', highlightedNodes)
    console.log('高亮连线:', highlightedFlows)

    // 6. 设置高亮
    setHighlights(highlightedNodes, highlightedFlows)

    // 7. 绑定节点事件
    bindNodeEvents()

    // 8. 初始化视图状态
    updateViewbox()

    title.value = `流程状态预览`
    console.log('流程图初始化完成')
  } catch (error: any) {
    console.error('加载流程图失败:', error)
    ElMessage.error('加载流程图失败: ' + error.message)
  } finally {
    loading.value = false
  }
})

// 清理资源
onBeforeUnmount(() => {
  if (bpmnViewer.value) {
    bpmnViewer.value.destroy()
  }
})

// 居中显示流程图
async function centerDiagram() {
  if (!bpmnViewer.value) return

  const canvas = bpmnViewer.value.get('canvas')
  const elementRegistry = bpmnViewer.value.get('elementRegistry')

  // 获取所有元素
  const elements = elementRegistry.getAll()

  if (elements.length === 0) {
    // 如果没有元素，使用默认的居中方式
    canvas.zoom('fit-viewport', 'auto')
    return
  }

  // 计算流程图的边界
  let minX = Infinity
  let minY = Infinity
  let maxX = -Infinity
  let maxY = -Infinity

  elements.forEach((element: any) => {
    if (element.x !== undefined && element.y !== undefined) {
      minX = Math.min(minX, element.x)
      minY = Math.min(minY, element.y)
      maxX = Math.max(maxX, element.x + (element.width || 0))
      maxY = Math.max(maxY, element.y + (element.height || 0))
    }
  })

  // 计算流程图的中心点
  const centerX = (minX + maxX) / 2
  const centerY = (minY + maxY) / 2

  // 获取画布尺寸
  const canvasElement = canvas._container
  const canvasWidth = canvasElement.clientWidth
  const canvasHeight = canvasElement.clientHeight

  // 设置视图框，使流程图居中
  canvas.viewbox({
    x: centerX - canvasWidth / 2 / zoom.value,
    y: centerY - canvasHeight / 2 / zoom.value,
    width: canvasWidth / zoom.value,
    height: canvasHeight / zoom.value
  })

  updateViewbox()
}

// 更新视图框信息
function updateViewbox() {
  if (!bpmnViewer.value) return

  const canvas = bpmnViewer.value.get('canvas')
  const viewbox = canvas.viewbox()

  currentViewbox.value = {
    x: viewbox.x,
    y: viewbox.y,
    width: viewbox.width,
    height: viewbox.height
  }
}

// 切换网格显示
function toggleGrid() {
  showGrid.value = !showGrid.value
}

// 拖拽模式切换
function toggleDragMode() {
  isDragMode.value = !isDragMode.value
  if (isDragMode.value) {
    ElMessage.info('已启用拖拽模式，点击并拖动可移动画布')
  } else {
    ElMessage.info('已禁用拖拽模式')
  }
}

// 鼠标按下事件
function handleMouseDown(event: MouseEvent) {
  if (!isDragMode.value || !bpmnViewer.value) return

  if (event.button === 0) { // 左键
    isDragging.value = true
    dragStart.value = {
      x: event.clientX,
      y: event.clientY
    }

    // 设置光标样式
    if (canvas.value) {
      canvas.value.style.cursor = 'grabbing'
    }

    event.preventDefault()
  }
}

// 鼠标移动事件
function handleMouseMove(event: MouseEvent) {
  if (!isDragging.value || !bpmnViewer.value) return

  const dx = event.clientX - dragStart.value.x
  const dy = event.clientY - dragStart.value.y

  const canvas = bpmnViewer.value.get('canvas')
  const currentViewbox = canvas.viewbox()

  // 计算新的视图位置
  const newX = currentViewbox.x - dx / currentViewbox.scale
  const newY = currentViewbox.y - dy / currentViewbox.scale

  // 移动画布
  canvas.viewbox({
    x: newX,
    y: newY,
    width: currentViewbox.width,
    height: currentViewbox.height
  })

  // 更新起始位置
  dragStart.value = {
    x: event.clientX,
    y: event.clientY
  }

  event.preventDefault()
}

// 鼠标释放事件
function handleMouseUp() {
  if (isDragging.value) {
    isDragging.value = false
    if (canvas.value) {
      canvas.value.style.cursor = isDragMode.value ? 'grab' : 'default'
    }
  }
}

// 鼠标离开画布事件
function handleMouseLeave() {
  if (isDragging.value) {
    isDragging.value = false
    if (canvas.value) {
      canvas.value.style.cursor = isDragMode.value ? 'grab' : 'default'
    }
  }
}

// 滚轮缩放事件
function handleWheel(event: WheelEvent) {
  if (!bpmnViewer.value) return

  event.preventDefault()

  const canvas = bpmnViewer.value.get('canvas')
  const currentViewbox = canvas.viewbox()
  const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()

  // 计算鼠标在画布中的位置（相对于画布中心）
  const mouseX = event.clientX - rect.left
  const mouseY = event.clientY - rect.top

  // 计算缩放中心点在画布坐标系中的位置
  const centerX = currentViewbox.x + (mouseX / currentViewbox.scale)
  const centerY = currentViewbox.y + (mouseY / currentViewbox.scale)

  // 计算缩放因子（滚轮向下缩小，向上放大）
  const zoomFactor = event.deltaY < 0 ? 1.1 : 0.9
  const newZoom = Math.max(0.2, Math.min(3, zoom.value * zoomFactor))

  if (newZoom !== zoom.value) {
    zoom.value = newZoom

    // 以鼠标位置为中心进行缩放
    canvas.zoom(newZoom, {x: centerX, y: centerY})
    updateViewbox()
  }
}

// 设置节点高亮
function setHighlights(nodeIds: string[], flowIds: string[]) {
  console.log("设置高亮 - 开始", {nodeIds, flowIds})

  if (!bpmnViewer.value) {
    console.warn("BPMN Viewer未初始化，无法设置高亮")
    return
  }

  const canvas = bpmnViewer.value.get('canvas')
  const elementRegistry = bpmnViewer.value.get('elementRegistry')

  if (!canvas || !elementRegistry) {
    console.error("无法获取canvas或elementRegistry")
    return
  }

  // 清除所有现有高亮
  const allElements = elementRegistry.getAll()
  allElements.forEach((element: any) => {
    canvas.removeMarker(element.id, 'bpmn-highlight-node')
    canvas.removeMarker(element.id, 'bpmn-highlight-flow')
    canvas.removeMarker(element.id, 'bpmn-highlight-gateway')
  })

  // 高亮节点
  nodeIds.forEach((nodeId: string) => {
    const element = elementRegistry.get(nodeId)
    if (element) {
      if (element.type.includes('Gateway')) {
        canvas.addMarker(element.id, 'bpmn-highlight-gateway')
      } else {
        canvas.addMarker(element.id, 'bpmn-highlight-node')
      }
      console.log(`节点高亮成功: ${nodeId}`)
    } else {
      console.warn(`未找到节点: ${nodeId}，无法添加高亮`)
    }
  })

  // 高亮连线
  flowIds.forEach((flowId: string) => {
    const element = elementRegistry.get(flowId)
    if (element) {
      canvas.addMarker(element.id, 'bpmn-highlight-flow')
      console.log(`连线高亮成功: ${flowId} (类型: ${element.type})`)
    } else {
      console.warn(`未找到连线: ${flowId}，无法添加高亮`)
    }
  })
}

// 绑定节点事件
function bindNodeEvents() {
  if (!bpmnViewer.value) return

  const eventBus = bpmnViewer.value.get('eventBus')

  // 节点鼠标悬停事件
  eventBus.on('element.hover', async (event: any) => {
    try {
      const nodeId = event.element.id

      // 只处理任务节点
      if (event.element.type.includes('Task')) {
        // 检查缓存
        if (nodeDetailsCache.value[nodeId]) {
          activeNode.value = nodeDetailsCache.value[nodeId]
          return
        }

        // 获取节点详情
        const details = await getNodeDetails(processInstanceId, nodeId)
        // 缓存结果
        nodeDetailsCache.value[nodeId] = details.data.data

        // 显示节点详情
        activeNode.value = {
          id: nodeId,
          name: event.element.name || event.element.type.split(':')[1],
          ...details.data.data
        }
      }
    } catch (error: any) {
      console.error('处理节点悬停事件失败:', error)
      ElMessage.error('获取节点信息失败: ' + error.message)
    }
  })

  // 节点鼠标离开事件
  eventBus.on('element.out', () => {
    activeNode.value = null
  })
}

// 获取状态标签类型
function getStatusType(status: string): string {
  switch (status) {
    case 'COMPLETED':
      return 'success'
    case 'ACTIVE':
      return 'warning'
    case 'NOT_STARTED':
      return 'info'
    default:
      return ''
  }
}

function getStatusStr(status: string): string {
  switch (status) {
    case 'COMPLETED':
      return '已审批'
    case 'ACTIVE':
      return '待审批'
    case 'NOT_STARTED':
      return '未开始'
    default:
      return '未知'
  }
}

function resetZoom(): void {
  zoom.value = 1
  // 重置后重新居中
  setTimeout(() => centerDiagram(), 100)
}

function handleCloseFlowStatus() {
  router.back()
}
</script>

<style scoped>
.bpmn-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  background: #fff;
  border-bottom: 1px solid #ebeef5;
  z-index: 10;
}

.header-left {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  align-items: center;
}

.header h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.bpmn-canvas-wrapper {
  flex: 1;
  min-height: 400px;
  position: relative;
  overflow: hidden;
  cursor: default;
  background-color: #fafafa;
}

.bpmn-canvas-wrapper.drag-mode {
  cursor: grab;
}

.bpmn-canvas-wrapper.drag-mode:active {
  cursor: grabbing;
}

.bpmn-canvas-wrapper.with-grid {
  background-color: #fff;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.9);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.loading-icon {
  font-size: 40px;
  color: #409eff;
  animation: rotating 2s linear infinite;
}

@keyframes rotating {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.node-details {
  padding: 16px;
  background: #f9fafc;
  border-top: 1px solid #ebeef5;
  z-index: 10;
}

.node-details h3 {
  margin-bottom: 12px;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.detail-row {
  display: flex;
  margin-bottom: 8px;
  align-items: center;
}

.label {
  font-weight: 600;
  width: 80px;
  color: #606266;
  flex-shrink: 0;
}

.value {
  flex: 1;
  color: #303133;
}

.approvers {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.approver-tag {
  margin-right: 6px;
}
</style>

<style>
/* 网格背景样式 */
.grid-background {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}

/* BPMN画布容器，确保在网格之上 */
.djs-container {
  position: relative;
  z-index: 1;
}

/* 修复SequenceFlow高亮问题的全局样式 */

/* 节点高亮样式 */
.bpmn-highlight-node {
  stroke: #f56c6c !important;
  stroke-width: 2px !important;
  fill: rgba(254, 240, 240, 0.9) !important;
}

.bpmn-highlight-node .djs-visual > rect {
  stroke: #f56c6c !important;
  stroke-width: 2px !important;
  fill: rgba(254, 240, 240, 0.9) !important;
}

/* 连线高亮样式 */
.bpmn-highlight-flow {
  stroke: #67c23a !important;
  stroke-width: 2px !important;
}

/* 专门针对SequenceFlow的路径元素 */
.bpmn-highlight-flow .djs-visual path {
  stroke: #67c23a !important;
  stroke-width: 2px !important;
}

/* 箭头标记高亮 */
.bpmn-highlight-flow marker path {
  fill: #67c23a !important;
  stroke: #67c23a !important;
}

/* 网关高亮样式 */
.bpmn-highlight-gateway {
  stroke: #e6a23c !important;
  stroke-width: 2px !important;
  fill: rgba(253, 246, 236, 0.9) !important;
}

.bpmn-highlight-gateway .djs-visual > polygon {
  stroke: #e6a23c !important;
  stroke-width: 2px !important;
  fill: rgba(253, 246, 236, 0.9) !important;
}

/* 修复SVG渲染模糊问题 */
.djs-element .djs-visual {
  shape-rendering: geometricPrecision;
}

.djs-shape {
  filter: none !important;
}

/* 确保文本清晰 */
.djs-label {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 12px;
  font-weight: 400;
  paint-order: stroke;
  stroke: white;
  stroke-width: 2px;
}

/* 修复缩放时的模糊问题 */
.djs-container {
  transform-style: preserve-3d;
  backface-visibility: hidden;
}
</style>